import time, os, sqlite3
from threading import Thread
import numpy as np
import pandas as pd
from tqsdk import TqApi, TqAuth, TqKq
from rich.console import Console
from rich.theme import Theme
from MyTT import REF, EMA, SUM

#改变控制台背景色和字体色，控制台窗口大小
os.system("COLOR 02")
os.system("mode con cols=150 lines=50")

# 定义颜色主题
# 定义更明亮显眼的颜色主题
custom_theme = Theme({
    "info": "bright_cyan",
    "warning": "bright_yellow",
    "error": "bright_red",
    "success": "bright_green",
    "trade": "bold bright_magenta"
})
console = Console(theme=custom_theme)

# 定义全局变量
symbols = []
api=None
threads = []
# stop_event = threading.Event()
# api = TqApi(account=TqKq(), auth=TqAuth("cps168", "alibaba"))


def get_symbols():
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM products WHERE is_monitored=1")
        products = cursor.fetchall()
        conn.close()
        symbols=[row[2] for row in products]
    except Exception as e:
        print(f"从数据库获取监控品种时出错: {e}", style="error")
        #print("数据库查询结果：",symbols)
    return symbols

# 新增函数，判断交易所是否支持市价单
def is_market_order_supported(symbol):
    unsupported_exchanges = ['CFFEX', 'SHFE', 'INE', 'SSE', 'SZSE']
    for exchange in unsupported_exchanges:
        if symbol.startswith(exchange):
            return False
    return True

def insert_order_with_check(api, symbol, direction, offset, volume, quote):
    try:
        if is_market_order_supported(symbol):
            # 若不支持 order_type 参数，尝试使用默认下单方式
            # 这里假设默认下单方式为限价单，使用最新价作为限价
            order = api.insert_order(
                symbol=symbol,
                direction=direction,
                offset=offset,
                volume=volume,
                limit_price=quote.last_price  # 限价单
            )
            api.wait_update()  # 等待订单状态更新
            if order.status == 'rejected' and '平今手数超过今仓持仓量' in order.reason:
                console.print(f"通知 cps168: 下单 {symbol} 已被服务器拒绝，原因: {order.reason}", style="error")
        else:
            # 不支持市价单时使用限价单，使用最新价作为限价
            order = api.insert_order(
                symbol=symbol,
                direction=direction,
                offset=offset,
                volume=volume,
                limit_price=quote.last_price  # 限价单
            )
            api.wait_update()  # 等待订单状态更新
            if order.status == 'rejected' and '平今手数超过今仓持仓量' in order.reason:
                console.print(f"通知 cps168: 下单 {symbol} 已被服务器拒绝，原因: {order.reason}", style="error")
    except Exception as e:
        console.print(f"下单 {symbol} 时出错: {e}", style="error")

def stop_loss(symbol, klines, quote, position):
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT limit_stoploss FROM products WHERE name=? AND is_monitored=1", (symbol,))
        result = cursor.fetchone()
        conn.close()
        if result is None:
            stop_loss_limit = 0
        else:
            stop_loss_limit = result[0]
    except Exception as e:
        console.print(f"从数据库获取 {symbol} 止损限额时出错: {e}", style="error")
        return

    console.print(f"{time.strftime('%X')} 开始检查{symbol}止损条件", style="warning")
    console.print(f"{time.strftime('%X')} 开始处理 {symbol}", style="warning") 
    if True:  # 条件一：api.is_changing(klines.iloc[-1], "datetime") 条件二：api.is_changing(klines.iloc[-1], "close") 条件三：api.is_changing(quote,["last_price", "bid_volume1", "ask_volume1"]) 
        console.print(f"{time.strftime('%X')} 数据更新", style="info")
        try:
            # ***************************************限额止损检查***************************************
            if position.pos_short > 0:
                short_loss_per_hand = (position.open_price_short - quote.last_price)*quote.volume_multiple * quote.price_tick
                if short_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        # 平今仓，每次平 1 手
                        while position.pos_short_today > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSETODAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今空仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                        # 平昨仓，每次平 1 手
                        while position.pos_short_his > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSEYESTERDAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨空仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                    else:
                        # 平空仓，每次平 1 手
                        while position.pos_short > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSE", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平{symbol}空仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓

            if position.pos_long > 0:
                long_loss_per_hand = (quote.last_price - position.open_price_long)*quote.volume_multiple * quote.price_tick
                if long_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        # 平今仓，每次平 1 手
                        while position.pos_long_today > 0:
                            insert_order_with_check(api, symbol, "SELL", "CLOSETODAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今多仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                        # 平昨仓，每次平 1 手
                        while position.pos_long_his > 0:
                            insert_order_with_check(api, symbol, "SELL", "CLOSEYESTERDAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨多仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                    else:
                        # 平多仓，每次平 1 手
                        while position.pos_long > 0:
                            insert_order_with_check(api, symbol, "SELL", "CLOSE", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平{symbol}多仓(限额止损): 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓

            # ***************************************趋势追踪止损检查***************************************
            close = klines.close
            low = klines.low
            open = klines.open
            high = klines.high
            # 转换为 numpy 数组，方便使用 MyTT 计算
            close = np.array(close)
            low = np.array(low)
            open = np.array(open)
            high = np.array(high)

            Q = (3 * close + low + open + high) / 6
            # 计算操盘线
            trading_line = (26 * Q + 25 * REF(Q, 1) + 24 * REF(Q, 2) + 23 * REF(Q, 3) + 22 * REF(Q, 4) + 21 * REF(Q, 5) + 20 * REF(Q, 6) + 19 * REF(Q, 7) + 18 * REF(Q, 8) + 17 * REF(Q, 9) + 16 * REF(Q, 10) + 15 * REF(Q, 11) + 14 * REF(Q, 12) + 13 * REF(Q, 13) + 12 * REF(Q, 14) + 11 * REF(Q, 15) + 10 * REF(Q, 16) + 9 * REF(Q, 17) + 8 * REF(Q, 18) + 7 * REF(Q, 19) + 6 * REF(Q, 20) + 5 * REF(Q, 21) + 4 * REF(Q, 22) + 3 * REF(Q, 23) + 2 * REF(Q, 24) + REF(Q, 26)) / 351
            # 计算空头线
            short_line = EMA(trading_line, 7)
            # 平仓条件判断
            print("条件值是：",trading_line[-2],short_line[-2])
            if len(trading_line) >= 2 and len(short_line) >= 2:
                # 处理空单
                if position.pos_short > 0 and trading_line[-2] > short_line[-2]:
                    if symbol.startswith('SHFE'):
                        # 平今仓，每次平 1 手
                        while position.pos_short_today > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSETODAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今空仓: 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                        # 平昨仓，每次平 1 手
                        while position.pos_short_his > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSEYESTERDAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨空仓: 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                    else:
                        # 平空仓，每次平 1 手
                        while position.pos_short > 0:
                            insert_order_with_check(api, symbol, "BUY", "CLOSE", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平{symbol}空仓: 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                # 处理多单
                if position.pos_long > 0 and trading_line[-2] < short_line[-2]:
                    if symbol.startswith('SHFE'):
                        # 平今仓，每次平 1 手
                        while position.pos_long_today > 0:
                            insert_order_with_check(api, symbol, "SELL", "CLOSETODAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今多仓: 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓
                        # 平昨仓，每次平 1 手
                        while position.pos_long_his > 0:
                            insert_order_with_check(api, symbol, "SELL", "CLOSEYESTERDAY", 1, quote)
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨多仓: 手数: 1",
                                style="trade"
                            )
                            position = api.get_position(symbol)  # 实时更新持仓

        except Exception as e:
            console.print(f"处理 {symbol} 止损逻辑时出错: {e}", style="error")   
    api.wait_update(deadline=time.time() + 1)


if __name__ == "__main__":
    try:
        # 方案一
        api = TqApi(account=TqKq(), auth=TqAuth("cps168", "alibaba"))
        symbols = get_symbols()        
        while True:
            deadline = time.time() + 2  # 设置超时时间为 2 秒
            api.wait_update(deadline=deadline)
            console.print(f"**********{time.strftime('%X')} **********", style="warning")
            time.sleep(5)
            for symbol in symbols:
                klines = api.get_kline_serial(symbol, 60, data_length=300)
                quote = api.get_quote(symbol)
                position = api.get_position(symbol)
                stop_loss(symbol, klines, quote, position)

    except Exception as e:
        pass
    finally:
        api.close()
        console.print("程序已停止", style="info")